﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interactivity;

namespace OmniKits.Windows.Behaviors
{
    public class KeyGestureInputBehavior
        : Behavior<TextBox>
    {
#pragma warning disable 1591

        public static readonly DependencyProperty KeyGestureProperty = KeyGestureInput.KeyGestureProperty.AddOwner(typeof(KeyGestureInputBehavior));
        public static readonly DependencyProperty ForcedModifiersProperty = KeyGestureInput.ForcedModifiersProperty.AddOwner(typeof(KeyGestureInputBehavior));
        public static readonly DependencyProperty AllowPureModifiersProperty = KeyGestureInput.AllowPureModifiersProperty.AddOwner(typeof(KeyGestureInputBehavior));

        public static bool GetAllowPureModifiers(TextBox textbox)
        {
            return textbox.GetAllowPureModifiers();
        }
        public static void SetAllowPureModifiers(TextBox textbox, bool value)
        {
            textbox.SetAllowPureModifiers(value);
        }

        public static ModifierKeys GetForcedModifiers(TextBox textbox)
        {
            return textbox.GetForcedModifiers();
        }
        public static void SetForcedModifiers(TextBox textbox, ModifierKeys value)
        {
            textbox.SetForcedModifiers(value);
        }

        public static RelaxKeyGesture GetKeyGesture(TextBox textbox)
        {
            return textbox.GetKeyGesture();
        }
        public static void SetKeyGesture(TextBox textbox, RelaxKeyGesture hotkey)
        {
            textbox.SetKeyGesture(hotkey);
        }

        private TextBox _InputBox;

        protected override void OnAttached()
        {
            this._InputBox = this.AssociatedObject;

            _InputBox.ContextMenu = null;

            DataObject.AddCopyingHandler(_InputBox, CancelCopying);
            DataObject.AddPastingHandler(_InputBox, CancelPasting);

            _InputBox.SelectionChanged += InputBox_SelectionChanged;
            _InputBox.PreviewDragEnter += InputBox_CancelDrag;
            //InputBox.PreviewDragLeave += InputBox_CancelDrag;
            _InputBox.PreviewDragOver += InputBox_CancelDrag;

            _InputBox.PreviewKeyDown += InputBox_PreviewKeyDown;
            _InputBox.PreviewKeyUp += InputBox_PreviewKeyUp;
        }

        protected override void OnDetaching()
        {
            _InputBox.ClearValue(FrameworkElement.ContextMenuProperty);

            DataObject.RemoveCopyingHandler(_InputBox, CancelCopying);
            DataObject.RemovePastingHandler(_InputBox, CancelPasting);

            _InputBox.SelectionChanged -= InputBox_SelectionChanged;
            _InputBox.PreviewDragEnter -= InputBox_CancelDrag;
            //InputBox.PreviewDragLeave -= InputBox_CancelDrag;
            _InputBox.PreviewDragOver -= InputBox_CancelDrag;

            _InputBox.PreviewKeyDown -= InputBox_PreviewKeyDown;
            _InputBox.PreviewKeyUp -= InputBox_PreviewKeyUp;

            this._InputBox = null;
        }

        #region guardian events

        private void CancelCopying(object sender, DataObjectCopyingEventArgs e)
        {
            e.CancelCommand();
        }
        private void CancelPasting(object sender, DataObjectPastingEventArgs e)
        {
            e.CancelCommand();
        }

        void InputBox_CancelDrag(object sender, DragEventArgs e)
        {
            e.Effects = DragDropEffects.None;
            e.Handled = true;
        }

        void InputBox_SelectionChanged(object sender, RoutedEventArgs e)
        {
            var text = _InputBox.Text;
            if (text == null) return;

            if (_InputBox.SelectionStart < text.Length)
                _InputBox.SelectionStart = text.Length;
            if (_InputBox.SelectionLength != 0)
                _InputBox.SelectionLength = 0;
        }

        #endregion

        private Key Key
        {
            get
            {
                return _InputBox.GetKey();
            }
            set
            {
                _InputBox.SetKey(value);
            }
        }

        private Key _LastKeyDown;
        private void InputBox_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            e.Handled = true;

            var key = e.Key;
            switch (key)
            {
                case Key.System:
                    key = e.SystemKey;
                    break;
                case Key.ImeProcessed:
                    return;
            }

            // to get rid of the repeating key shit
            if (key == this._LastKeyDown)
                return;
            else
                this._LastKeyDown = key;

            if (RelaxKeyGesture.IsModifierKey(key))
            {
                if (this.Key != 0 && Keyboard.IsKeyUp(this.Key))
                    this.Key = Key.None;
            }
            else
            {
                this.Key = key;
            }

            _InputBox.SetModifiers(KeyGestureInput.GetKeyboardModifiers());

            _InputBox.UpdateKeyGesture();
        }

        void InputBox_PreviewKeyUp(object sender, KeyEventArgs e)
        {
            e.Handled = true;

            var key = e.Key;
            switch (key)
            {
                case Key.System:
                    key = e.SystemKey;
                    break;
                case Key.ImeProcessed:
                    return;
            }

            // to get rid of the repeating key shit
            if (key == this._LastKeyDown)
                this._LastKeyDown = 0;

            if (RelaxKeyGesture.IsModifierKey(key))
            {
                if (this.Key == 0)
                {
                    if (_InputBox.GetAllowPureModifiers())
                        return;
                }
                else
                {
                    if (Keyboard.IsKeyUp(this.Key))
                        return;
                }

                _InputBox.SetModifiers(KeyGestureInput.GetKeyboardModifiers());
            }
            else
            {
                return;
            }

            _InputBox.UpdateKeyGesture();
        }
    }
}
